/*
 * Copyright 2012-2021 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.boot.autoconfigure.condition;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import org.springframework.context.annotation.Conditional;
import org.springframework.core.env.Environment;

/**
 * {@link Conditional @Conditional} 条件注解，用于检查指定的属性是否具有特定值。
 * <p>
 * 默认情况下，属性必须存在于 {@link Environment} 中，并且<strong>不等于</strong> {@code false}。
 * 可以通过 {@link #havingValue()} 和 {@link #matchIfMissing()} 进行进一步定制。
 *
 * <p>
 * {@link #havingValue} 属性用于指定属性应有的值。下表展示了根据属性值与 {@link #havingValue()} 不同取值时的匹配情况：
 *
 * <table border="1">
 * <caption>值匹配规则</caption>
 * <tr>
 * <th>属性值</th>
 * <th>{@code havingValue=""}</th>
 * <th>{@code havingValue="true"}</th>
 * <th>{@code havingValue="false"}</th>
 * <th>{@code havingValue="foo"}</th>
 * </tr>
 * <tr><td>{@code "true"}</td>  <td>是</td><td>是</td><td>否</td><td>否</td></tr>
 * <tr><td>{@code "false"}</td> <td>否</td><td>否</td><td>是</td><td>否</td></tr>
 * <tr><td>{@code "foo"}</td>   <td>是</td><td>否</td><td>否</td><td>是</td></tr>
 * </table>
 *
 * <p>
 * 如果属性在 {@link Environment} 中不存在，则会参考 {@link #matchIfMissing()}。
 * 默认情况下，缺失属性不会匹配（{@code false}）。
 *
 * <p>
 * ⚠ 注意：该条件不能可靠地用于匹配集合类型的属性，例如：
 *
 * <pre class="code">
 * &#064;ConditionalOnProperty(prefix = "spring", name = "example.values")
 * class ExampleAutoConfiguration {
 * }
 * </pre>
 *
 * 在上述例子中，如果 {@code spring.example.values} 存在则匹配，
 * 但如果仅 {@code spring.example.values[0]} 存在则不会匹配。
 * 这类情况更适合使用自定义条件。
 *
 * @author Maciej Walkowiak
 * @author Stephane Nicoll
 * @author Phillip Webb
 * @since 1.1.0
 */
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE, ElementType.METHOD })
@Documented
@Conditional(OnPropertyCondition.class)
public @interface ConditionalOnProperty {

	/**
	 * {@link #name()} 的别名。
	 * @return 属性名数组
	 */
	String[] value() default {};

	/**
	 * 属性名前缀，如果未以 "." 结尾则会自动补上。
	 * 格式应为由点分隔的单词（如 {@code "acme.system.feature"}）。
	 * @return 属性名前缀
	 */
	String prefix() default "";

	/**
	 * 要检查的属性名。如果定义了 prefix，会拼接成完整的属性 key。
	 * 例如：prefix = {@code app.config}，name = {@code my-value}
	 * => 完整属性名 {@code app.config.my-value}。
	 * 推荐使用短横线分隔的小写格式（如 {@code my-long-property}）。
	 * @return 属性名数组
	 */
	String[] name() default {};

	/**
	 * 期望的属性值（字符串形式）。若未指定，则匹配条件为属性<strong>不等于</strong> {@code false}。
	 * @return 期望值
	 */
	String havingValue() default "";

	/**
	 * 若属性不存在，是否依然匹配。默认不匹配（false）。
	 * @return 当属性缺失时是否匹配
	 */
	boolean matchIfMissing() default false;

}
